#!/usr/bin/env python

import nmap # import nmap.py module
import sys
import vlc
import time
import socket
import pymysql
import datetime as dt
import os
import sys

from PyQt5.QtCore import QObject
from PyQt5.QtGui import QTextCursor
from PyQt5.QtCore import QStringListModel
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget
import threading
from Bartender import Bartender
from FileSystem import FileSystem
from MainWin import *



#创造一个名为FullScreenWidget的窗口类，继承自Qwidget
class FullScreenWidget(QWidget):

    def __init__(self,parent=None):
        super(FullScreenWidget, self).__init__(parent)
        self.initUI()

    def keyPressEvent(self, QKeyEvent):
        if QKeyEvent.key() == Qt.Key_Escape:  # 判断是否按下了A键
            self.close()

    def setMainWindow(self,mainWindow):
        self.mainWindow=mainWindow  #不知道能不能直接传入对象窗口

    #初始化窗口
    def initUI(self):
        #设置窗口在屏幕中的位置与窗口的大小
        # self.setGeometry(300,300,250,150)
        self.setWindowTitle('全屏显示')




class MyWindow(QMainWindow, Ui_MainWindow):

    signal_ListView_set = QtCore.pyqtSignal(list)  # 建立信号变量

    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent)
        self.setupUi(self)

        self.bartender = Bartender()                # Bartender打印引擎
        self.my_file_sys = FileSystem()             # 创建日志
        self.signal_connect()  # 信号与槽函数绑定


        self.PlayFullWidget = FullScreenWidget()  #全屏显示窗口
        self.lineEditSN.setFocus() #设定 sn 默认焦点
        self.isFullScreen=False #全局变量是否全屏。
        self.currentIP="127.0.0.1" #保存当前检测的设备坐标
        self.qList = []  # 存储ip列表
        self.g_bExit = False  # 线程是否退出状态标识
        self.ThreadsleepTime=0.2 #线程睡眠时间
          # creating a basic vlc instance
        self.instance = vlc.Instance()
         # creating an empty vlc media player
        self.mplayer = self.instance.media_player_new()
        self.fullMplayer=self.instance.media_player_new()




        # self.start_ScancIP()


    # 信号与槽函数绑定
    def signal_connect(self):
        # 软件启动时列表刷新
        self.scan_printer_list_slot()
        self.scan_btwfile_list_slot()
        # 试打印group
        # self.bnt_tryReadFile.clicked.connect(self.try_read_file_slot)
        # self.bnt_tryModifySourceContent.clicked.connect(self.try_modify_source_content_slot)
        self.PrintButton.clicked.connect(self.try_print_slot)
        self.cmbBtw.clicked.connect(self.scan_btwfile_list_slot)              # 扫描btw
        self.cmbBtw.currentIndexChanged.connect(self.btwfile_changed_slot)    # 切换btw
        # self.SubstringList.currentIndexChanged.connect(self.source_changed_slot) #切换数据源
        # 打印机
        self.cmbPrint.clicked.connect(self.scan_printer_list_slot)              # 扫描打印机
        # 其他内部信号
        self.bartender.eventSignal.connect(self.bartender_event_slot)  # 打印引擎的事件信息

        self.signal_ListView_set.connect(self.update_listView) #绑定信号
        self.listView.clicked.connect(self.clickedlist)  # listview 的点击事件
        # self.butCheckFinish.clicked.connect(self.check_Finish)
        self.butQuite.clicked.connect(self.close)
        # self.butFullScreen.clicked.connect(self.fullScreenPlay)

    def bartender_event_slot(self, msg):
        '''
        打印引擎事件
        :param msg:
        :return:
        '''
        # 监控bartender所有打印事件，当打印机打印完成后，会触发"任务发送"的事件
        self.my_log_print(msg)
        if msg.find("发送") > 0:
            self.my_log_print("打印机打印完成！")


    def try_read_file_slot(self, filename=None):
        '''
        读取btw内容的槽函数
        对比btw内容字段是否正确
        :param filename:
        :return:
        '''
        try:
            # 1.清空UI显示
            # self.lineEdit_sourceCount.clear()
            # self.SubstringList.clear()
            # self.lineEdit_sourceContent.clear()
            # 2.设置btwfile，该函数会自动关闭保存旧的btw文件，然后打开新的btw文件
            res = self.bartender.set_btwfile_using(self.cmbBtw.currentText())
            # 3.读取btw文件回显到UI
            if res:
                data_dict = self.bartender.get_data_dict()
                # self.lineEdit_sourceCount.setText(str(len(data_dict)))
                # for key in data_dict.keys():
                    # self.SubstringList.addItem(str(key))
                # self.SubstringList.setCurrentIndex(0)
                # self.lineEdit_sourceContent.setText(data_dict[str(self.SubstringList.currentText())])
                res1 = self.checkSource(data_dict)
                print(data_dict)
                self.my_log_print("试读取文件成功")
                print("试读取文件成功")
                return res1
        except Exception as ex:
            print(ex)

    def checkSource(self,data_dict=None):
        '''
        检测btw模板是否和这个模板吻合
        :param data_dict:
        :return:
        '''
        if 'SN' in data_dict and 'IP' in data_dict and 'MAC' in data_dict :
            print('标签正常')
            return True
        else :
            print('标签不正常')
            return False


    def source_changed_slot(self):
        '''
        数据源变更槽函数
        :return:
        '''
        try:
            data_dict = self.bartender.get_data_dict()
            self.lineEdit_sourceContent.setText(data_dict[str(self.SubstringList.currentText())])
            self.my_log_print("试读取数据源成功")
        except Exception as ex:
            print(ex)

    def scan_printer_list_slot(self):
        '''
        打印机列表扫描槽函数
        :return:
        '''
        self.my_log_print("扫描打印机并刷新列表")
        self.cmbPrint.clear()
        printers, default_printer = self.bartender.get_printer_list()
        for printer in printers:
            self.cmbPrint.addItem(printer, None)
        self.cmbPrint.setCurrentText(default_printer)

    def scan_btwfile_list_slot(self, targetfile=None):
        '''
        btw标签模板列表槽函数
        :param targetfile:
        :return:
        '''
        try:
            folder_path = os.getcwd()  # 获取当前路径
            file_list = os.listdir(folder_path + "\\btw\\")
            if targetfile:
                self.my_log_print("寻找："+str(targetfile)+"...")
                time.sleep(0.1)
                for file in file_list:
                    if file == targetfile:
                        self.my_log_print("已找到：" + str(targetfile) + "！")
                        return True
                return False
            if file_list:
                self.my_log_print("扫描btw文件并刷新列表")
                self.cmbBtw.clear()
                for file in file_list:
                    if file[-4] == "." and file[-3] == "b" and file[-2] == "t" and file[-1] == "w":
                        # 填充文件列表
                        self.cmbBtw.addItem(file, None)
        except Exception as ex:
            # self.warning_signal.emit("scan_btwfile_list_slot 出错！！！" + str(ex))
            print(ex)

    def btwfile_changed_slot(self):
        '''
        btw标签模板改变槽函数
        :return:
        '''

        # 1.清空UI显示
        try:
            self.lineEdit_sourceCount.clear()
            self.SubstringList.clear()
            self.lineEdit_sourceContent.clear()
            self.bartender.close_btwfile()
        except Exception as ex:
            # self.warning_signal.emit("btwfile_changed_slot 出错！！！" + str(ex))
            print(ex)

    def try_modify_source_content_slot(self,data_dict):
        '''
        修改数据源数据
        :return:
        '''
        try:
            # dict = {}
             #打印前保存数据
            # 打开数据库连接
            db = pymysql.connect("127.0.0.1", "root", "yxx520520", "cameracheck")
        except Exception as ex:
            print(ex)

        try:
            # 使用cursor()方法创建一个游标对象cursor
            cursor = db.cursor()
            CheckDate = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            data = (data_dict['SN'], data_dict['MAC'], data_dict['EUI'], CheckDate)
            # 插入数据
            sql = "INSERT INTO camerainfo (SN, MAC, EUI,CheckDate) VALUES ( '%s', '%s','%s','%s' )"
            cursor.execute(sql % data)
            db.commit()
            db.close()
            # dict[self.SubstringList.currentText()] = str(self.lineEdit_sourceContent.text())

            self.bartender.set_data_dict(data_dict)
            self.my_log_print("完成修改数据源")
            print('完成修改数据源')
        except Exception as ex:
            #错误数据回滚
            sqldel="DELETE FROM camerainfo WHERE SN='%s' AND MAC='%s' AND CheckDate='%s'"
            cursor.execute(sql % data)
            # self.warning_signal.emit("try_modify_source_content_slot 出错！！！" + str(ex))
            print(ex)


    def my_log_print(self, text):
        '''
        操作日志输出
        :param text:
        :return:
        '''
        self.my_log_print_thread = threading.Thread(target=self.my_log_print_thread_loop, daemon=True, args=(text,))
        self.my_log_print_thread.start()


    def my_log_print_thread_loop(self, text):
        '''
        操作日志工作线程
        :param text:
        :return:
        '''
        # 获取当前时间
        now_time = dt.datetime.now().strftime('%T') + " : "
        text = now_time + text + '\n'
        # 由于使用append追加文本显示时会自动移除以前的内容，只保留50行
        # self.LogPlain.append(text)     # 显示在UI，MaximumBlockCount属性提前在QT中设为50
        # self.LogPlain.moveCursor(QTextCursor.End)
        self.my_file_sys.logcat_into_file(text)   # 打印在txt文件

    def try_print_slot(self):
        '''
        打印槽函数
        :return:
        '''

        #打印标签流程，先读取btw内容


        if self.try_read_file_slot() : #读取标签模板
            #******写入字典数据
            data_dict = {}
            data_dict['EUI'] = self.lineEditEUI.text()
            data_dict['MAC'] = self.lineEditMAC.text()
            data_dict['SN'] = self.lineEditSN.text()
            #**************

            print('打印数据：' , data_dict)
        self.try_modify_source_content_slot(data_dict)


        if self.bartender.btFormat:
            nResult=0
            # nResult = self.bartender.my_print(self.PrintersList.currentText())
            if nResult == 0:
                self.my_log_print("打印API调用成功")
                print("打印API调用成功")
            elif nResult == 1:
                self.my_log_print("打印API调用失败:超时\n")
                print("打印API调用失败:超时\n")
            else:
                self.my_log_print("打印API调用失败:其他原因\n")
                print("打印API调用失败:其他原因\n")
        else:
            self.my_log_print("试打印失败，未打开标签文件")
            print("试打印失败，未打开标签文件")



    def close(self) -> bool:
        self.PlayFullWidget.close()

    def keyPressEvent(self, QKeyEvent):
    #     '''
    #     全局键盘事件
    #     :param a0:
    #     :return:
    #     '''
        if QKeyEvent.key() == Qt.Key_Enter:  # 判断是否按下了A键
            self.lineEditSN.setFocus()

    # def fullScreenPlay(self):
    #     '''
    #     #检车清晰度的时候切换到全屏幕
    #     :return:
    #     '''
    #     # TODO 添加全屏代码
    #
    #     self.PlayFullWidget.showFullScreen()
    #
    #
    #
    #     if (self.isFullScreen==False):
    #         self.fullMplayer.stop()
    #         self.fullMplayer.release()
    #         # creating an empty vlc media player
    #         self.fullMplayer = self.instance.media_player_new()
    #         media = self.instance.media_new("rtsp://admin:admin@" + self.currentIP + ":8554/live0.264")
    #         media.get_mrl()
    #         self.fullMplayer.set_media(media)
    #         self.fullMplayer.set_hwnd(self.PlayFullWidget.winId())  # 设定Qt窗体的控件的 句柄为显示窗口
    #         self.PlayFullWidget.showMaximized()
    #         self.fullMplayer.play()  # 开始显示
    #         QApplication.processEvents()

    # def check_Finish(self):
    #     '''
    #     #检测完成后存储数据到MYsql数据库表 cameracheck中
    #     :return:
    #     '''
    #     #TODO 添加完成检测后的代码
    #
    #     # 打开数据库连接
    #     db = pymysql.connect("127.0.0.1", "root", "yxx520520", "cameracheck")
    #     # 使用cursor()方法创建一个游标对象cursor
    #     cursor = db.cursor()
    #
    #     #数据写入变量
    #     SN = self.lineEditSN.text()
    #     # if (self.radioQXDOK.clicked ):
    #     #     QingXiDu =1
    #     # else:
    #     #     QingXiDu =0
    #     # if (self.radioYPOK.clicked):
    #     #     YinPin=1
    #     # else:
    #     #     YinPin=0
    #     # if(self.radioRYZHNG.clicked):
    #     #     RiYeZhuanHuan=1
    #     # else:
    #     #     RiYeZhuanHuan=0
    #     CheckDate =time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    #     data=(SN,QingXiDu,YinPin,RiYeZhuanHuan,CheckDate)
    #     # 插入数据
    #     sql = "INSERT INTO camerainfo (SN, QingXiDu, YinPin, RiYeZhuanHuan,CheckDate) VALUES ( '%s', '%d', '%d','%d','%s' )"
    #     cursor.execute(sql % data)
    #     db.commit()
    #     db.close()
    #
    #     self.mplayer.stop()
    #     # self.mplayer.release()

    #线程更新ListView的工作函数
    def update_listView(self,hosts_list):
        slm = QStringListModel();  # 创建mode
        self.qList.clear()  # 重置清空列表
        IP=self.get_local_IP()
        for host, status in hosts_list:
            if(host!=IP):
                self.qList.append('{0}'.format(host))
                print('{0}'.format(host))
        slm.setStringList(self.qList)  # 将数据设置到model
        self.listView.setModel(slm)  ##绑定 listView 和 model



    def openCamera(self,currentIP):
        """
        打开相机开始显示
        :return:
        """
        self.mplayer.stop()
        self.mplayer.release()
         # creating an empty vlc media player
        self.mplayer = self.instance.media_player_new()
        media = self.instance.media_new("rtsp://admin:admin@"+ currentIP+ ":8554/live0.264")
        media.get_mrl()
        self.mplayer.set_media(media)
        self.mplayer.set_hwnd(self.playWidget.winId()) #设定Qt窗体的控件的 句柄为显示窗口
        self.mplayer.set_fullscreen(True)
        self.mplayer.play()   #开始显示
        QApplication.processEvents()


    def PlayPause(self):
        if self.mediaplayer.is_playing():
            return
        else:
            if self.mediaplayer.play() == -1:
                self.openCamera()
                return
            self.mediaplayer.play()


    def updateUI(self):

        self.positionslider.setValue(self.mediaplayer.get_position() * 1000)
        if not self.mediaplayer.is_playing():
            return




    def clickedlist(self, qModelIndex):
        # QMessageBox.information(self, "QListView", "你选择了: " + self.qList[qModelIndex.row()])
        # print("点击的是：" + str(qModelIndex.row()))
        self.currentIP=self.qList[qModelIndex.row()]
        self.openCamera(self.currentIP)


    #开始监控IP线程
    def start_ScancIP(self):
        self.g_bExit = False
        try:
            hThreadHandle = threading.Thread(target=self.work_thread, args=(), daemon=True)
            hThreadHandle.start()
        except:
            print("error: unable to start thread")

    #监控实时扫描的线程
    def work_thread(self):
        '''
        :return:
        '''
        while True:
            time.sleep(self.ThreadsleepTime) #每隔0.2秒查询一次
            try:
                nm = nmap.PortScanner()  # instantiate nmap.PortScanner object
                nm.scan(hosts='192.168.1.0/24', arguments='-n -sP -PE -PA21,80')
                hosts_list = [(x, nm[x]['status']['state']) for x in nm.all_hosts()]
                self.signal_ListView_set.emit(hosts_list)
            except:
                print("error:scan port error!")
            if self.g_bExit == True:
                break

    #获得本机IP
    def get_local_IP(self):
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            ip = s.getsockname()[0]
        finally:
            s.close()

        return ip

if __name__ == '__main__':
    app = QApplication(sys.argv)

    myWin = MyWindow()
    myWin.show()
    sys.exit(app.exec_())









